home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus 2002 #11 / Amiga Plus CD - 2002 - No. 11.iso / Tools / Development / ncurses-5.3 / ncurses / tinfo / lib_setup.c < prev    next >
Encoding:
C/C++ Source or Header  |  2002-10-27  |  12.1 KB  |  438 lines

  1. /****************************************************************************
  2.  * Copyright (c) 1998-2001,2002 Free Software Foundation, Inc.              *
  3.  *                                                                          *
  4.  * Permission is hereby granted, free of charge, to any person obtaining a  *
  5.  * copy of this software and associated documentation files (the            *
  6.  * "Software"), to deal in the Software without restriction, including      *
  7.  * without limitation the rights to use, copy, modify, merge, publish,      *
  8.  * distribute, distribute with modifications, sublicense, and/or sell       *
  9.  * copies of the Software, and to permit persons to whom the Software is    *
  10.  * furnished to do so, subject to the following conditions:                 *
  11.  *                                                                          *
  12.  * The above copyright notice and this permission notice shall be included  *
  13.  * in all copies or substantial portions of the Software.                   *
  14.  *                                                                          *
  15.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
  16.  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
  17.  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
  18.  * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
  19.  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
  20.  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
  21.  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
  22.  *                                                                          *
  23.  * Except as contained in this notice, the name(s) of the above copyright   *
  24.  * holders shall not be used in advertising or otherwise to promote the     *
  25.  * sale, use or other dealings in this Software without prior written       *
  26.  * authorization.                                                           *
  27.  ****************************************************************************/
  28.  
  29. /****************************************************************************
  30.  *  Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995               *
  31.  *     and: Eric S. Raymond <esr@snark.thyrsus.com>                         *
  32.  ****************************************************************************/
  33.  
  34. /*
  35.  * Terminal setup routines common to termcap and terminfo:
  36.  *
  37.  *        use_env(bool)
  38.  *        setupterm(char *, int, int *)
  39.  */
  40.  
  41. #include <curses.priv.h>
  42. #include <tic.h>        /* for MAX_NAME_SIZE */
  43. #include <term_entry.h>
  44.  
  45. #if SVR4_TERMIO && !defined(_POSIX_SOURCE)
  46. #define _POSIX_SOURCE
  47. #endif
  48.  
  49. #include <term.h>        /* lines, columns, cur_term */
  50.  
  51. MODULE_ID("$Id: lib_setup.c,v 1.70 2002/10/12 21:50:18 tom Exp $")
  52.  
  53. /****************************************************************************
  54.  *
  55.  * Terminal size computation
  56.  *
  57.  ****************************************************************************/
  58.  
  59. #if HAVE_SIZECHANGE
  60. # if !defined(sun) || !TERMIOS
  61. #  if HAVE_SYS_IOCTL_H
  62. #   include <sys/ioctl.h>
  63. #  endif
  64. # endif
  65. #endif
  66.  
  67. #if NEED_PTEM_H
  68.  /* On SCO, they neglected to define struct winsize in termios.h -- it's only
  69.   * in termio.h and ptem.h (the former conflicts with other definitions).
  70.   */
  71. # include <sys/stream.h>
  72. # include <sys/ptem.h>
  73. #endif
  74.  
  75. /*
  76.  * SCO defines TIOCGSIZE and the corresponding struct.  Other systems (SunOS,
  77.  * Solaris, IRIX) define TIOCGWINSZ and struct winsize.
  78.  */
  79. #ifdef TIOCGSIZE
  80. # define IOCTL_WINSIZE TIOCGSIZE
  81. # define STRUCT_WINSIZE struct ttysize
  82. # define WINSIZE_ROWS(n) (int)n.ts_lines
  83. # define WINSIZE_COLS(n) (int)n.ts_cols
  84. #else
  85. # ifdef TIOCGWINSZ
  86. #  define IOCTL_WINSIZE TIOCGWINSZ
  87. #  define STRUCT_WINSIZE struct winsize
  88. #  define WINSIZE_ROWS(n) (int)n.ws_row
  89. #  define WINSIZE_COLS(n) (int)n.ws_col
  90. # endif
  91. #endif
  92.  
  93. static int _use_env = TRUE;
  94.  
  95. static void do_prototype(void);
  96.  
  97. NCURSES_EXPORT(void)
  98. use_env(bool f)
  99. {
  100.     T((T_CALLED("use_env()")));
  101.     _use_env = f;
  102.     returnVoid;
  103. }
  104.  
  105. NCURSES_EXPORT_VAR(int) LINES = 0;
  106. NCURSES_EXPORT_VAR(int) COLS = 0;
  107. NCURSES_EXPORT_VAR(int) TABSIZE = 0;
  108.  
  109. static void
  110. _nc_get_screensize(int *linep, int *colp)
  111. /* Obtain lines/columns values from the environment and/or terminfo entry */
  112. {
  113.     /* figure out the size of the screen */
  114.     T(("screen size: terminfo lines = %d columns = %d", lines, columns));
  115.  
  116.     if (!_use_env) {
  117.     *linep = (int) lines;
  118.     *colp = (int) columns;
  119.     } else {            /* usually want to query LINES and COLUMNS from environment */
  120.     int value;
  121.  
  122.     *linep = *colp = 0;
  123.  
  124.     /* first, look for environment variables */
  125.     if ((value = _nc_getenv_num("LINES")) > 0) {
  126.         *linep = value;
  127.     }
  128.     if ((value = _nc_getenv_num("COLUMNS")) > 0) {
  129.         *colp = value;
  130.     }
  131.     T(("screen size: environment LINES = %d COLUMNS = %d", *linep, *colp));
  132.  
  133. #ifdef __EMX__
  134.     if (*linep <= 0 || *colp <= 0) {
  135.         int screendata[2];
  136.         _scrsize(screendata);
  137.         *colp = screendata[0];
  138.         *linep = screendata[1];
  139.         T(("EMX screen size: environment LINES = %d COLUMNS = %d",
  140.            *linep, *colp));
  141.     }
  142. #endif
  143. #if HAVE_SIZECHANGE
  144.     /* if that didn't work, maybe we can try asking the OS */
  145.     if (*linep <= 0 || *colp <= 0) {
  146.         if (isatty(cur_term->Filedes)) {
  147.         STRUCT_WINSIZE size;
  148.  
  149.         errno = 0;
  150.         do {
  151.             if (ioctl(cur_term->Filedes, IOCTL_WINSIZE, &size) < 0
  152.             && errno != EINTR)
  153.             goto failure;
  154.         } while
  155.             (errno == EINTR);
  156.  
  157.         /*
  158.          * Solaris lets users override either dimension with an
  159.          * environment variable.
  160.          */
  161.         if (*linep <= 0)
  162.             *linep = WINSIZE_ROWS(size);
  163.         if (*colp <= 0)
  164.             *colp = WINSIZE_COLS(size);
  165.         }
  166.         /* FALLTHRU */
  167.       failure:;
  168.     }
  169. #endif /* HAVE_SIZECHANGE */
  170.  
  171.     /* if we can't get dynamic info about the size, use static */
  172.     if (*linep <= 0) {
  173.         *linep = (int) lines;
  174.     }
  175.     if (*colp <= 0) {
  176.         *colp = (int) columns;
  177.     }
  178.  
  179.     /* the ultimate fallback, assume fixed 24x80 size */
  180.     if (*linep <= 0) {
  181.         *linep = 24;
  182.     }
  183.     if (*colp <= 0) {
  184.         *colp = 80;
  185.     }
  186.  
  187.     /*
  188.      * Put the derived values back in the screen-size caps, so
  189.      * tigetnum() and tgetnum() will do the right thing.
  190.      */
  191.     lines = (short) (*linep);
  192.     columns = (short) (*colp);
  193.     }
  194.  
  195.     T(("screen size is %dx%d", *linep, *colp));
  196.  
  197.     if (VALID_NUMERIC(init_tabs))
  198.     TABSIZE = (int) init_tabs;
  199.     else
  200.     TABSIZE = 8;
  201.     T(("TABSIZE = %d", TABSIZE));
  202.  
  203. }
  204.  
  205. #if USE_SIZECHANGE
  206. NCURSES_EXPORT(void)
  207. _nc_update_screensize(void)
  208. {
  209.     int my_lines, my_cols;
  210.  
  211.     _nc_get_screensize(&my_lines, &my_cols);
  212.     if (SP != 0 && SP->_resize != 0)
  213.     SP->_resize(my_lines, my_cols);
  214. }
  215. #endif
  216.  
  217. /****************************************************************************
  218.  *
  219.  * Terminal setup
  220.  *
  221.  ****************************************************************************/
  222.  
  223. #define ret_error(code, fmt, arg)    if (errret) {\
  224.                         *errret = code;\
  225.                         returnCode(ERR);\
  226.                     } else {\
  227.                         fprintf(stderr, fmt, arg);\
  228.                         exit(EXIT_FAILURE);\
  229.                     }
  230.  
  231. #define ret_error0(code, msg)        if (errret) {\
  232.                         *errret = code;\
  233.                         returnCode(ERR);\
  234.                     } else {\
  235.                         fprintf(stderr, msg);\
  236.                         exit(EXIT_FAILURE);\
  237.                     }
  238.  
  239. #if USE_DATABASE || USE_TERMCAP
  240. static int
  241. grab_entry(const char *const tn, TERMTYPE * const tp)
  242. /* return 1 if entry found, 0 if not found, -1 if database not accessible */
  243. {
  244.     char filename[PATH_MAX];
  245.     int status;
  246.  
  247.     /*
  248.      * $TERM shouldn't contain pathname delimiters.
  249.      */
  250.     if (strchr(tn, '/'))
  251.     return 0;
  252.  
  253. #if USE_DATABASE
  254.     if ((status = _nc_read_entry(tn, filename, tp)) != 1) {
  255.  
  256. #if !PURE_TERMINFO
  257.     /*
  258.      * Try falling back on the termcap file.
  259.      * Note:  allowing this call links the entire terminfo/termcap
  260.      * compiler into the startup code.  It's preferable to build a
  261.      * real terminfo database and use that.
  262.      */
  263.     status = _nc_read_termcap_entry(tn, tp);
  264. #endif /* PURE_TERMINFO */
  265.  
  266.     }
  267. #else
  268.     status = _nc_read_termcap_entry(tn, tp);
  269. #endif
  270.  
  271.     /*
  272.      * If we have an entry, force all of the cancelled strings to null
  273.      * pointers so we don't have to test them in the rest of the library.
  274.      * (The terminfo compiler bypasses this logic, since it must know if
  275.      * a string is cancelled, for merging entries).
  276.      */
  277.     if (status == 1) {
  278.     int n;
  279.     for_each_boolean(n, tp) {
  280.         if (!VALID_BOOLEAN(tp->Booleans[n]))
  281.         tp->Booleans[n] = FALSE;
  282.     }
  283.     for_each_string(n, tp) {
  284.         if (tp->Strings[n] == CANCELLED_STRING)
  285.         tp->Strings[n] = ABSENT_STRING;
  286.     }
  287.     }
  288.     return (status);
  289. }
  290. #endif
  291.  
  292. NCURSES_EXPORT_VAR(char) ttytype[NAMESIZE] = "";
  293.  
  294. /*
  295.  *    setupterm(termname, Filedes, errret)
  296.  *
  297.  *    Find and read the appropriate object file for the terminal
  298.  *    Make cur_term point to the structure.
  299.  *
  300.  */
  301.  
  302. NCURSES_EXPORT(int)
  303. setupterm(NCURSES_CONST char *tname, int Filedes, int *errret)
  304. {
  305.     struct term *term_ptr;
  306.     int status;
  307.  
  308.     START_TRACE();
  309.     T((T_CALLED("setupterm(%s,%d,%p)"), _nc_visbuf(tname), Filedes, errret));
  310.  
  311.     if (tname == 0) {
  312.     tname = getenv("TERM");
  313.     if (tname == 0 || *tname == '\0') {
  314.         ret_error0(-1, "TERM environment variable not set.\n");
  315.     }
  316.     }
  317.     if (strlen(tname) > MAX_NAME_SIZE) {
  318.     ret_error(-1, "TERM environment must be <= %d characters.\n",
  319.           MAX_NAME_SIZE);
  320.     }
  321.  
  322.     T(("your terminal name is %s", tname));
  323.  
  324.     term_ptr = typeCalloc(TERMINAL, 1);
  325.  
  326.     if (term_ptr == 0) {
  327.     ret_error0(-1, "Not enough memory to create terminal structure.\n");
  328.     }
  329. #if USE_DATABASE || USE_TERMCAP
  330.     status = grab_entry(tname, &term_ptr->type);
  331. #else
  332.     status = 0;
  333. #endif
  334.  
  335.     /* try fallback list if entry on disk */
  336.     if (status != 1) {
  337.     const TERMTYPE *fallback = _nc_fallback(tname);
  338.  
  339.     if (fallback) {
  340.         term_ptr->type = *fallback;
  341.         status = 1;
  342.     }
  343.     }
  344.  
  345.     if (status == -1) {
  346.     ret_error0(-1, "terminals database is inaccessible\n");
  347.     } else if (status == 0) {
  348.     ret_error(0, "'%s': unknown terminal type.\n", tname);
  349.     }
  350.  
  351.     /*
  352.      * Improve on SVr4 curses.  If an application mixes curses and termcap
  353.      * calls, it may call both initscr and tgetent.  This is not really a
  354.      * good thing to do, but can happen if someone tries using ncurses with
  355.      * the readline library.  The problem we are fixing is that when
  356.      * tgetent calls setupterm, the resulting Ottyb struct in cur_term is
  357.      * zeroed.  A subsequent call to endwin uses the zeroed terminal
  358.      * settings rather than the ones saved in initscr.  So we check if
  359.      * cur_term appears to contain terminal settings for the same output
  360.      * file as our current call - and copy those terminal settings.  (SVr4
  361.      * curses does not do this, however applications that are working
  362.      * around the problem will still work properly with this feature).
  363.      */
  364.     if (cur_term != 0) {
  365.     if (cur_term->Filedes == Filedes)
  366.         term_ptr->Ottyb = cur_term->Ottyb;
  367.     }
  368.  
  369.     set_curterm(term_ptr);
  370.  
  371.     if (command_character && getenv("CC"))
  372.     do_prototype();
  373.  
  374.     strncpy(ttytype, cur_term->type.term_names, NAMESIZE - 1);
  375.     ttytype[NAMESIZE - 1] = '\0';
  376.  
  377.     /*
  378.      * Allow output redirection.  This is what SVr3 does.  If stdout is
  379.      * directed to a file, screen updates go to standard error.
  380.      */
  381.     if (Filedes == STDOUT_FILENO && !isatty(Filedes))
  382.     Filedes = STDERR_FILENO;
  383.     cur_term->Filedes = Filedes;
  384.  
  385.     /*
  386.      * If an application calls setupterm() rather than initscr() or newterm(),
  387.      * we will not have the def_prog_mode() call in _nc_setupscreen().  Do it
  388.      * now anyway, so we can initialize the baudrate.
  389.      */
  390.     if (isatty(Filedes)) {
  391.     def_prog_mode();
  392.     baudrate();
  393.     }
  394.  
  395.     _nc_get_screensize(&LINES, &COLS);
  396.  
  397.     if (errret)
  398.     *errret = 1;
  399.  
  400.     T((T_CREATE("screen %s %dx%d"), tname, LINES, COLS));
  401.  
  402.     if (generic_type) {
  403.     ret_error(0, "'%s': I need something more specific.\n", tname);
  404.     }
  405.     if (hard_copy) {
  406.     ret_error(1, "'%s': I can't handle hardcopy terminals.\n", tname);
  407.     }
  408.     returnCode(OK);
  409. }
  410.  
  411. /*
  412. **    do_prototype()
  413. **
  414. **    Take the real command character out of the CC environment variable
  415. **    and substitute it in for the prototype given in 'command_character'.
  416. **
  417. */
  418.  
  419. static void
  420. do_prototype(void)
  421. {
  422.     int i;
  423.     char CC;
  424.     char proto;
  425.     char *tmp;
  426.  
  427.     tmp = getenv("CC");
  428.     CC = *tmp;
  429.     proto = *command_character;
  430.  
  431.     for_each_string(i, &(cur_term->type)) {
  432.     for (tmp = cur_term->type.Strings[i]; *tmp; tmp++) {
  433.         if (*tmp == proto)
  434.         *tmp = CC;
  435.     }
  436.     }
  437. }
  438.